#include "Swimmer.h"
#include "..\..\Constants.h"

Swimmer::~Swimmer(void) {
}

// ----------------------------------------------------------
// Init method
// ----------------------------------------------------------
void Swimmer::init() {
}

// ---------------------------------------------
// creates new entries by altering the starting
// x position
// ---------------------------------------------
void Swimmer::create(uint32 total) {
	if ( m_Entries.size() == 0 ) {
		float angle = 0.0f;
		float y = 20.0f;// + rand() * 30.0f;
		for ( int i = 0; i < total; ++i ) {
			Entry e;		
			ds::Vec2 startPos(0.0f,y);
			ds::Vec2 endPos(1024.0f,y+20.0f);
			if ( m_Left ) {
				e.velocity = ds::Vec2(1,0);
				angle = 0.0f;
			}
			else {
				startPos.x = 1024.0f;
				endPos.x = 0.0f;
				e.velocity = ds::Vec2(-1,0);
				angle = DEGTORAD(180.0f);			
			}
			startPos.x -= i * 50.0f * e.velocity.x;
			y += 30.0f;
			e.start = startPos;
			e.end = endPos;
			e.energy = SWIMMER_ENERGY;
			e.sprite = new ds::Sprite(startPos,SWIMMER_HEAD);
			e.sprite->rotation = angle;
			e.handle = m_CD.addCircle(startPos,ds::Vec2(17,15),15,SWIMMER_ID);
			e.timer = rand()* 0.6f;//0.0f;
			e.targetting = false;		
			ds::Vec2 tailPos = startPos;
			for ( int j = 0; j < TAIL_COUNT; ++j ) {
				tailPos.x -= 20.0f * e.velocity.x;
				e.tails.push_back(new ds::Sprite(tailPos,SWIMMER_TAIL));
			}
			m_Entries.push_back(e);
		}
		m_Targetting = false;
		m_Left = !m_Left;
	}
}

// ------------------------------------------------
//
// ------------------------------------------------
void Swimmer::update(float elapsed) {	
	moveAll(elapsed);
	// remove all that are out of scope
	Entries::iterator it = m_Entries.begin();
	while ( it != m_Entries.end() ) {
		if ( it->sprite->position.y > 780.0f ) {	
			delete it->sprite;
			m_CD.remove(it->handle);
			//FIXME: remove tail as well
			it = m_Entries.erase(it);			
		}
		else {
			++it;
		}
	}
	// draw all swimmers and each tail
	for ( size_t i = 0; i < m_Entries.size(); ++i ) {
		Entry* e = &m_Entries[i];
		addSprite(e->sprite);
		for ( size_t j = 0; j < e->tails.size(); ++j ) {
			addSprite(e->tails[j]);
		}
	}
}

void Swimmer::moveAll(float elapsed) {
	// move swimmers
	for ( size_t i = 0; i < m_Entries.size(); ++i ) {
		Entry* e = &m_Entries[i];
		e->timer += elapsed;
		ds::Vec2 vel = e->velocity;
		if ( m_Targetting ) {
			vel.x = sin(e->timer * 5.0f) * 0.5f;
		}
		else {
			vel.y = sin(e->timer * 5.0f) * 0.25f;
		}
		e->sprite->position.addScale(vel,elapsed*200.0f);
		if ( !m_Targetting ) {
			checkMovement(e);				
		}	
		moveTail(e);
		m_CD.setPosition(e->handle,e->sprite->position);
	}	
	checkTargettting();
}

void Swimmer::checkMovement(Entry* e) {
	bool right = true;
	if ( e->velocity.x < 0.0f ) {
		right = false;
	}
	// we are moving to the right
	if ( right ) {
		if ( e->sprite->position.x > 1024.0f ) {
			e->start.x = 1022.0f;
			e->end.y += 50;
			e->end.x = 0.0f;
			e->sprite->rotation = DEGTORAD(180.0f);
			e->velocity.x = -1.0f;
			e->timer = 0.0f;
		}
	}
	else {
		if ( e->sprite->position.x < 0.0f ) {
			e->start.x = 5.0f;
			e->end.y += 50;
			e->end.x = 1024.0f;
			e->sprite->rotation = 0.0f;
			e->velocity.x = 1.0f;
			e->timer = 0.0f;
		}
	}					
}
// ------------------------------------------------
//
// ------------------------------------------------
void Swimmer::removeByHandle(ds::CDHandle handle) {
	Entries::iterator it = m_Entries.begin();
	while ( it != m_Entries.end() ) {
		if ( it->handle == handle ) {	
			delete it->sprite;
			m_CD.remove(it->handle);
			//FIXME: remove tail as well
			it = m_Entries.erase(it);			
		}
		else {
			++it;
		}
	}
}

int Swimmer::handleHit(ds::CDHandle handle) {
	Entries::iterator it = m_Entries.begin();
	while ( it != m_Entries.end() ) {
		if ( it->handle == handle ) {	
			int energy = it->energy - SWIMMER_HIT;
			if ( it->energy <= 0 ) {
				delete it->sprite;
				m_CD.remove(it->handle);
				//FIXME: remove tail as well
				it = m_Entries.erase(it);							
			}
			else {
				it->energy = energy;
				++it;
			}
			return energy;
		}
		else {
			++it;
		}
	}
	return -1;
}

void Swimmer::clear() {
	Entries::iterator it = m_Entries.begin();
	while ( it != m_Entries.end() ) {
		delete it->sprite;
		m_CD.remove(it->handle);
		it = m_Entries.erase(it);							
	}
}
// ------------------------------------------------
// check whether we need to switch to targetting
// ------------------------------------------------
void Swimmer::checkTargettting() {
	if ( !m_Targetting ) {
		for ( size_t i = 0; i < m_Entries.size(); ++i ) {
			Entry* e = &m_Entries[i];
			float delta = abs(m_Target.x - e->sprite->position.x);
			if ( delta < TARGET_DISTANCE ) {
				m_Targetting = true;
			}
		}
		if ( m_Targetting ) {
			for ( size_t i = 0; i < m_Entries.size(); ++i ) {
				Entry* e = &m_Entries[i];			
				e->sprite->rotation = DEGTORAD(90.0f);
				e->velocity = ds::Vec2(0,2);
				for ( size_t j = 0; j < TAIL_COUNT; ++j ) {
					e->tails[j]->rotation = DEGTORAD(90.0f);
				}
			}
		}
	}
}

// ---------------------------------------------
// Moves the tail for a given entity
// ---------------------------------------------
void Swimmer::moveTail(Entry* e) {
	ds::Sprite* fsp = e->tails[0];
	ds::Vec2 tt = getCorrectedTarget(e);
	float add = 0.2f;
	if ( m_Targetting ) {
		add = 0.3f;
	}
	ds::Vec2 np = getNewPosition(tt,fsp->position,5.0f,add);
	fsp->position = np;
	for ( size_t j = 1; j < TAIL_COUNT; ++j ) {
		ds::Sprite* sp = e->tails[j];
		ds::Vec2 np = getNewPosition(e->tails[j-1]->position,sp->position,5.0f,add);
		sp->position = np;
	}
}

// ---------------------------------------------
// Get the updated target position 
// ---------------------------------------------
ds::Vec2 Swimmer::getCorrectedTarget(Entry* e) {
	ds::Vec2 tt = e->sprite->position;
	if ( e->velocity.x < 0.0f ) {
		tt.x += 20.0f;
	}
	else if ( e->velocity.x > 0.0f ) {
		tt.x -= 2.0f;
	}
	else {
		tt.x += 10.0f;
	}
	if ( e->velocity.y != 0.0f ) {
		tt.y -= 2.0f;
	}
	else {
		tt.y += 5.0f;
	}
	return tt;
}

